module ecs {
    /**
     * 允许方便的var-arg添加系统，管理器。支持插件
     */
    export class WorldConfigurationBuilder{
        private _systems: Bag<ConfigurationElement<BaseSystem>>;
        private _fieldResolvers: Bag<ConfigurationElement<FieldResolver>>;
        private _alwaysDelayComponentRemoval: boolean = false;
        private _cache: InjectionCache;
        private invocationStrategy: SystemInvocationStrategy;

        constructor(){
            this.reset();
            this._cache = InjectionCache.get();
        }

        /**
         * 用系统组装世界
         */
        public build(): WorldConfiguration {
            let config = new WorldConfiguration();
            this.registerSystem(config);
            this.registerFieldResolvers(config);
            this.registerInvocationStrategies(config);
            config.setAlwaysDelayComponentRemoval(this._alwaysDelayComponentRemoval);
            this.reset();
            return config;
        }

        private registerInvocationStrategies(config: WorldConfiguration){
            if (this.invocationStrategy != null){
                config.setInvocationStrategy(this.invocationStrategy);
            }
        }

        private registerSystem(config: WorldConfiguration){
            for (let i = 0; i < this._systems.size(); i ++){
                let configurationElement = this._systems.get(i);
                config.setSystem(configurationElement.item);
            }
        }

        public registerFieldResolvers(config: WorldConfiguration){
            if (this._fieldResolvers.size() > 0){
                // TODO: sort
                let fieldHandler = new FieldHandler(InjectionCache.get());

                for (let i = 0; i < this._fieldResolvers.size(); i ++){
                    let configurationElement = this._fieldResolvers.get(i);
                    fieldHandler.addFieldResolver(configurationElement.item);
                }

                config.setInjector(new CachedInjector().setFieldHandler(fieldHandler));
            }
        }

        /**
         * 指定对系统/插件的依赖。
         * @param priority 优先级更高的先注册。插件不支持
         * @param types 所需系统。
         */
        public dependsOn(priority: number = Priority.NORMAL, ...types: any[]): WorldConfigurationBuilder{
            for (let type in types){
                try {
                    switch (this._cache.getFieldClassType(types[type])){
                        case ClassType.SYSTEM:
                            this.dependsOnSystem(priority, types[type]);
                            break;
                        default:
                            // TODO：插件
                            break;
                    }
                } catch(err){
                    throw new Error("Unable to instance" + type + " via reflection.");
                }
            }

            return this;
        }

        /**
         * 激活注册系统
         * @param priority 
         * @param types 
         */
        public with(priority: number = Priority.NORMAL, ...systems: BaseSystem[]){
            this.addSystems(priority, systems);
            return this;
        }

        /**
         * 添加字段解析器。
         * @param fieldResolvers 
         */
        public register(...fieldResolvers: FieldResolver[]){
            for (let i = 0; i < fieldResolvers.length; i ++){
                let fieldResolver = fieldResolvers[i];
                this._fieldResolvers.add(ConfigurationElement.of(fieldResolver));
            }

            return this;
        }

        protected dependsOnSystem(priority: number, type: BaseSystem){
            if (!this.containsType(this._systems, egret.getQualifiedSuperclassName(type))){
                this._systems.add(ConfigurationElement.of(type, priority));
            }
        }

        /**
         * 队列系统注册的帮助方法
         * @param priority 
         * @param systems 
         */
        private addSystems(priority: number, systems: BaseSystem[]){
            for (let i = 0; i < systems.length; i ++){
                let system = systems[i];
                if (this.containsType(this._systems, egret.getQualifiedSuperclassName(system))){
                    throw new Error("System of type " + system + " registered twice. Only once allowed.")
                }

                this._systems.add(new ConfigurationElement<BaseSystem>(system, priority));
            }
        }

        /**
         * 检查registerables包是否包含任何传递的类型
         * @param items 
         * @param type 
         */
        private containsType(items: Bag<ConfigurationElement<any>>, type: any): boolean{
            for (let i = 0; i < items.size(); i ++){
                if (items.get(i).itemType == type)
                    return true;
            }

            return false;
        }

        private reset(){
            this.invocationStrategy = null;
            this._fieldResolvers = new Bag<ConfigurationElement<FieldResolver>>();
            this._systems = new Bag<ConfigurationElement<BaseSystem>>();
            this._alwaysDelayComponentRemoval = false;
        }

        /**
         * 延迟组件删除，直到通知所有订阅。
         * @param value 
         */
        public alwaysDelayComponentRemoval(value: boolean): WorldConfigurationBuilder{
            this._alwaysDelayComponentRemoval = value;
            return this;
        }
    }

    /**
     * 对于优先级，越高的值优先级越高。可能会改变。
     */
    export abstract class Priority{
        public static LOWEST: number = Number.MIN_VALUE;
        public static LOW: number = -10000;
        public static OPERATIONS = -1000;
        public static NORMAL = 0;
        public static HIGH = 10000;
        public static HIGHEST = Number.MAX_VALUE;
    }
}